package ru.amse.stroganova.ui.tool.state;

import java.awt.Point;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;

import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;

import ru.amse.stroganova.presentation.EdgePresentation;
import ru.amse.stroganova.ui.GraphComponent;
import ru.amse.stroganova.ui.command.Command;
import ru.amse.stroganova.ui.tool.Tool;

class WeightChangeState extends ToolState {

	private final GraphComponent component;
	
	private final Tool tool;

	private final JSpinner weightChooser;

	private final SpinnerNumberModel spinnerNumberModel;
	
	private final JSpinner.DefaultEditor editor;
	
	private final EdgePresentation edge;

	private final static int WEIGHT_SPINNER_WIDTH = 40;
	
	private final static int WEIGHT_SPINNER_HEIGHT = 20;

	WeightChangeState(GraphComponent component, Tool parentTool, EdgePresentation edge, int weight) {
		this.component = component;
		this.edge = edge;
		tool = parentTool;
		component.getEditingActionsFactory().getDeleteAction().setEnabled(false);
		
		spinnerNumberModel = new SpinnerNumberModel(edge.getWeight(), -1000, 1000, 1);
		weightChooser = new JSpinner(spinnerNumberModel);
		KeyListener keyAdapter = new KeyAdapter() {

			@Override
			public void keyPressed(KeyEvent e) {
				if (e.getKeyCode() == KeyEvent.VK_ENTER) {
					weightChanged();
					WeightChangeState.this.tool.setState(new DefaultState(WeightChangeState.this.component, WeightChangeState.this.tool));
				} else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
					changeCancelled();
				}
			}
		};
		
		weightChooser.addKeyListener(keyAdapter);
		editor = ((JSpinner.DefaultEditor) weightChooser.getEditor());
		editor.getTextField().addKeyListener(keyAdapter);
		
		weightChooser.setVisible(true);
		Point point = edge.getUpperLeftWeightPoint();
		weightChooser.setBounds(point.x - WEIGHT_SPINNER_WIDTH / 4, point.y - EdgePresentation.WEIGHT_SHIFT,
				WEIGHT_SPINNER_WIDTH, WEIGHT_SPINNER_HEIGHT);
		this.component.addTempComponent(weightChooser);
		weightChooser.grabFocus();
	}

	@Override
	public void mousePressed(MouseEvent e) {
		weightChanged();
		if (component.getGraphElementSelection().select(e.getPoint())) {
			component.getGraphElementSelection().unselectItem(e.getPoint());
			tool.setState(new DefaultState(component, tool, e));
		} else {
			tool.setState(new RectangleSelectionState(component, tool, e.getPoint(), new DefaultState(component, tool)));
		}
	}

	private void weightChanged() {
		int newWeight = 0;
		try {
			newWeight = Integer.parseInt(editor.getTextField().getText());
		} catch (NumberFormatException e) {
			return;
		}
		if ((newWeight < (Integer) spinnerNumberModel.getMinimum()) || (newWeight > (Integer) spinnerNumberModel.getMaximum())) {
			return;
		}
		if (newWeight != edge.getWeight()) {
			Command command = component.getCommandFactory().getWeightChangeCommand(edge.getWeight(), newWeight, edge);
			component.addCommand(command);
			command.execute();
		}
		component.removeTempComponent(weightChooser);
	}

	private void changeCancelled() {
		component.removeTempComponent(weightChooser);
		tool.setState(new DefaultState(component, tool));
	}
}

